import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;

class SortingOrder {
	public String sort;
	public String order;
	//public String subSort;
	//public String subOrder;	
	
	public SortingOrder() {
		this.sort =
		this.order = ""; 
	//	this.subSort = 
	//	this.subOrder = "";
	}
	
	public SortingOrder(String sort, String order) {
		this.sort = sort;
		this.order = order;
	}
}


class SearchScriptMetaData extends MetaData {
	
	private String conditions = "";
	
	public SearchScriptMetaData()
	{
		System.out.println("TEST SearchScriptMetaData!");
	}
	
	public void setResultsDelimiter(String delimiter) {
		ConnDB.setMultiFieldsDisjoint(delimiter);
	}
	
	public void setPublicationTypes(String type) throws MP2Exception {
		String types[] = type.split(",");
		if (types.length == 1)
			ConnDB.setType(types[0]);
		else 
			ConnDB.setTypes(types);
	}
	
	public String getTotalRecords() throws MP2Exception {
		String result = "0";
		ConnDB.setConditionString(this.conditions);
		try {
			result = ConnDB.getTotalRecordsRelated();
		} catch (SQLException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBGetResultSetErr);
			e.printStackTrace();
			throw mp2;
		}
		this.conditions = ConnDB.getConditions();
		try {
			ConnDB.cleanResource();
		} catch (SQLException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBCleaningErr);
			e.printStackTrace();
			throw mp2;
		}
		return result;
	}
	
	public void setMultiFilters(LinkedList<String[]> filter, Hashtable<String, String> relation) throws MP2Exception {
		char multi = ',';
		if (!this.conditions.trim().equals(""))
			return;
		int index = 0;
		for (int i = 0; i < filter.size(); i++) {
			String[] filters = filter.get(i);
			if (filters[1].trim().equals(""))
				continue;
			ConnDB.setupMultiFiltersQueryString(filters[0], filters[1], multi + "");
			if (relation.get(i + "") != null) {
				ConnDB.addConjunction(index, relation.get(i + ""));
			}
			index++;
		}
	}
	
	public void setLimit(int startPoint, int rows) {
		String[] limit = {(startPoint - 1) * rows + "", rows + ""};
		ConnDB.setLimit(limit);
	}
	
	public String produce() throws MP2Exception {
		ConnDB.setConditionString(this.conditions);
		return super.produce();
	}
	
}

class PublicationListMetaData extends MetaData {
	private boolean PublicationListFlag = false;
	private String PublicationType[];
	protected PublicationListCitationFactory CitaFactory = new PublicationListCitationFactory();
	
	public void setPeerReviewedPrefix(String prefix) {
		CitaFactory.setXMLPrefix(prefix);
	}
	
	public void setPeerReviewedNamespaceURI(String uri) {
		CitaFactory.setXMLNamespaceURI(uri);
	}
	
	private void setViaType() throws MP2Exception {
		String types[] = this.PublicationType[1].split(",");
		if (types.length == 1)
			ConnDB.setType(types[0]);
		else 
			ConnDB.setTypes(types);
	}
	
	public void setPublicationType(String types[]) {
		this.PublicationType = types;
		CitaFactory.setPublicationType(types);
	}
	
	public void setPeerReviewedXPath(String xpath) {
		this.PublicationListFlag = true;
		CitaFactory.setPeerReviewedXPath(xpath);
	}
	
	protected void produceViaDB() throws MP2Exception {
		if ((this.PublicationType != null) && (this.PublicationListFlag)) {
			this.setViaType();
		}
		super.produceViaDB();
	}
}

public class MetaData {
	
	protected ArrayList<String> Fields = new ArrayList<String>();
	protected LinkedList<String[]> Filters = new LinkedList<String[]>();
	protected LinkedList<SortingOrder> SortingOrder = new LinkedList<SortingOrder>(); 
	//private SortingOrder SortingOrder = new SortingOrder();
	protected ConnectDB ConnDB = new ConnectDB();
	protected CitationFactory CitaFactory = new CitationFactory();
	protected String ResultSet[];
	protected String MultiResultSet[];
	protected String TempDirectory = "";
	protected String StyleSheet = "";
	protected String MappingFile = "";
	protected String TempFileSuffix = "";
	protected String ConfFile = "";
	protected String TokenHeader = "";
	protected String TokenEnd = "";
	protected String WebRoot = "";
	protected String MetaData = "";
	protected String Fedora	= "";
	
	public void reset() {
		this.Filters = new LinkedList<String[]>();
		this.SortingOrder = new LinkedList<SortingOrder>();
		//this.SortingOrder = new SortingOrder();
		
	}
	
	public void addField(String field) throws MP2Exception {
		ConnDB.addField(field);
	}
	
	public void setSorting(String sort, String order) {
		this.SortingOrder.addFirst(new SortingOrder(sort, order));
		//this.SortingOrder.sort = sort;
		//this.SortingOrder.order = order;
	}
	
	public void setSubSorting(String subSort, String subOrder) {
		this.SortingOrder.addLast(new SortingOrder(subSort, subOrder));
		//this.SortingOrder.subSort = subSort;
		//this.SortingOrder.subOrder = subOrder;
	}
	
	public void setFilters() throws MP2Exception {
		Iterator<String[]> iter = Filters.iterator();
		while (iter.hasNext()) {
			String key[] = (String[] ) iter.next();
			ConnDB.setFieldsCondition(key[0], key[1]);
		}
	}
	
	public void setFilters(String field, String filter) {
		String filters[] = {field, filter};
		this.Filters.add(filters);
	}
	
	public void setFiltersWildCards(String field, String filter) {
		String filters[] = {field, ConnectDB.setWildcard(filter)};
		this.Filters.add(filters);
	}
	
	public void setTempDirectory(String dir) {
		this.TempDirectory = dir;
	}
	
	public void setXSLFile(String xsl) {
		this.StyleSheet = xsl;
	}
	
	public void setMappingFile(String mapping) {
		this.MappingFile = mapping;
	}
	
	public void setTempFileSuffix(String suf) {
		this.TempFileSuffix = suf;
	}
	
	public void setConfFile(String conf) {
		this.ConfFile = conf;
	}
	
	public void setWebRoot(String root) {
		this.WebRoot = root;
	}
	
	public void cleanCached() {
		CitaFactory.reset();	
	}
	
	public void setMetaData(String metadata) {
		this.MetaData = metadata;
	}
	
	public void setFedora(String fedora) {
		this.Fedora = fedora;
	}
	
	public void clean() throws MP2Exception {
		try {
			ConnDB.clean();
		} catch (SQLException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBCleaningErr);
			e.printStackTrace();
			throw mp2;
		}
	}
	
	public void setupSearchModel() throws MP2Exception {
		this.setupDBModel();
	}
	
	private void setupDBModel() throws MP2Exception {
		ConnDB.initDB();
		try {
			ConnDB.setMapping(this.MappingFile);
		} catch (IOException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBMappingReadErr);
			e.printStackTrace();
			throw mp2;
		}
		try {
			ConnDB.settingDBConf(this.ConfFile);
		} catch (Exception e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.ReadingConfFileErr);
			e.printStackTrace();
			throw mp2;
		}
		
		try {
			ConnDB.connDB();
		} catch (ClassNotFoundException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.JDBCClassNotFoundErr);
			e.printStackTrace();
			throw mp2;
		} catch (SQLException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBConnectionErr);
			e.printStackTrace();
			throw mp2;
		}
		
		ConnDB.setOrder(SortingOrder);
		ConnDB.setTable();
	}
	
	public void setupOrder() throws MP2Exception {
		ConnDB.setOrder(SortingOrder);
	}

	public void setupMetaDataModel() {
		CitaFactory.setWebRoot(WebRoot);
		CitaFactory.setTempDirectory(TempDirectory);
		CitaFactory.setConfFile(ConfFile);
		CitaFactory.setStyleSheet(StyleSheet);
		CitaFactory.setMetaData(MetaData);
		CitaFactory.setFedora(Fedora);
		CitaFactory.addHeader(TokenHeader);
		CitaFactory.addFeet(TokenEnd);
		CitaFactory.setFileSuffix(TempFileSuffix);
		CitaFactory.cleanTempFile(TempFileSuffix);
	}
	
	public String[] getMultiResults() {
		return MultiResultSet;
	}
	
	public String[] getResults() {
		return ResultSet;
	}
	
	protected void produceViaDB() throws MP2Exception {
		
		this.setFilters();
		try {
			ConnDB.sendSQL();
		} catch (SQLException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBSendingSQLErr);
			e.printStackTrace();
			throw mp2;
		}
		try {
			ResultSet = ConnDB.getResultSet();
			MultiResultSet = ConnDB.getMultipleResults();
		} catch (SQLException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBGetResultSetErr);
			e.printStackTrace();
			throw mp2;
		}
		try {
			ConnDB.cleanResource();
		} catch (SQLException e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.DBCleaningErr);
			e.printStackTrace();
			throw mp2;
		}
	}
	
	public String produce() throws MP2Exception {
		this.produceViaDB();
		String file = "";
		if ((ResultSet == null) || (ResultSet.length == 0))
			return null;		
		try {
			 file = CitaFactory.produce(ResultSet);
		} catch (Exception e) {
			MP2Exception mp2 = new MP2Exception();
			mp2.setMessage(MP2Exception.CitationModuleErr);
			e.printStackTrace();
			throw mp2;
		}
		return file;
	}
	
	public void addHeader(String token) {
		this.TokenHeader = token;
	}
	
	public void addFeet(String token) {
		this.TokenEnd = token;
	}
}
